package main

import (
	"errors"
	"fmt"
	"reflect"
)

type Student struct {
	Name  string `json:"name"`
	Age   int
	Score float64
}

func (student Student) SayHello() string {
	return "hello, i am " + student.Name
}

func (student Student) HowOld() int {
	return student.Age
}

func (student Student) GetSum(a float64, b float64) float64 {
	return a + b
}

func ReflectStruct(v interface{}) {

	typ := reflect.TypeOf(v)
	val := reflect.ValueOf(v)

	kind := val.Kind()

	if kind != reflect.Struct {
		return
	}

	fieldCount := typ.NumField()

	for i := 0; i < fieldCount; i++ {
		field := typ.Field(i)
		fieldVal := val.Field(i)
		jsonName := field.Tag.Get("json")
		fmt.Printf("%d, %v, %v, %v, %v\n", i+1, field.Name, field.Type, fieldVal, jsonName)
	}

	// 调用方法
	method := val.MethodByName("GetSum")
	name, _ := typ.MethodByName("GetSum")
	args := []reflect.Value{reflect.ValueOf(1.0), reflect.ValueOf(2.0)}
	result := method.Call(args)
	fmt.Printf(
		"%v.%T, funcName=%v, args=%v, result=%0.2f\n",
		typ,
		method.Interface(),
		name.Name,
		[]float64{args[0].Float(), args[1].Float()},
		result[0].Float())

	m := method.Interface()
	f := m.(func(float64, float64) float64)(1, 2)
	fmt.Println(f)
}

func ChangeFieldValue(v interface{}, fieldName string, targetValue interface{}) (bool, error) {

	val := reflect.ValueOf(v)

	// 获取kind
	kind1 := val.Kind()

	if kind1 != reflect.Ptr {
		return false, errors.New("不是ptr")
	}

	elem := val.Elem()

	if elem.Kind() != reflect.Struct {
		return false, errors.New("不是结构体")
	}

	field := elem.FieldByName(fieldName)
	field.Set(reflect.ValueOf(targetValue))

	return true, nil
}

func main() {

	student := Student{
		Name:  "tom",
		Age:   10,
		Score: 10,
	}
	ReflectStruct(student)

	fmt.Println("---")
	_, err := ChangeFieldValue(student, "Name", "jerry")
	if err != nil {
		fmt.Printf("err=%v\n", err)
	} else {
		fmt.Println(student)
	}
}
